import StorageByWebDav from "@/module/storage/entity/WebStorage/StorageByWebDav";
import FileListItem from "../domain/FileListItem";
import Driver from "../service/Driver";
import { createClient, FileStat, ResponseDataDetailed, WebDAVClient } from "webdav";
import { parseFileExtra } from "@/utils/FieldUtil";

export default class WebDavDriver implements Driver {

    private readonly client: WebDAVClient;

    constructor(storage: StorageByWebDav) {
        this.client = createClient(storage.url, {
            username: storage.username,
            password: storage.password,
        })
    }

    getFileDownloadLink(path: string): string {
        return this.client.getFileDownloadLink(path);
    }

    copyFile(path: string, destination: string): Promise<void> {
        return this.client.copyFile(path, destination);
    }

    moveFile(path: string, destinationPath: string): Promise<void> {
        return this.client.moveFile(path, destinationPath);
    }

    async list(path: string): Promise<FileListItem[]> {
        let files = await this.client.getDirectoryContents(path);
        // @ts-ignore
        if (files['data']) {
            files = files as ResponseDataDetailed<Array<FileStat>>
            return Promise.resolve(files.data.map(e => {
                return {
                    name: e.basename,
                    path: e.filename,
                    folder: e.type === 'directory',
                    updateTime: e.lastmod,
                    size: e.size,
                    extra: parseFileExtra(e.basename, e.type === 'directory')
                }
            }));
        } else {
            files = files as Array<FileStat>;
            return Promise.resolve(files.map(e => {
                return {
                    name: e.basename,
                    path: e.filename,
                    folder: e.type === 'directory',
                    updateTime: e.lastmod,
                    size: e.size,
                    extra: parseFileExtra(e.basename, e.type === 'directory')
                }
            }));
        }
    }

    mkdir(name: string, path: string): Promise<void> {
        return this.client.createDirectory(path + '/' + name);
    }

    rename(name: string, newName: string, path: string): Promise<void> {
        return this.client.moveFile(`${path}/${name}`, `${path}/${newName}`);
    }

    rm(path: string): Promise<void> {
        return this.client.deleteFile(path)
    }

    readText(path: string, progress?: (current: number, total: number) => void): Promise<string> {
        return new Promise<string>((resolve, reject) => {
            this.client.getFileContents(path, {
                onDownloadProgress: (e) => {
                    if (progress) {
                        progress(e.loaded, e.total)
                    }
                }
            })
                .then((content: ArrayBuffer) => {
                    let fileReader = new FileReader();
                    fileReader.readAsText(new Blob([content]), 'utf-8');
                    fileReader.onload = function (evt: ProgressEvent<FileReader>) {
                        if (evt.target) {
                            resolve(evt.target.result as string);
                        }
                    }

                }).catch(e => reject(e));
        });
    }

    writeText(path: string, content: string, append: boolean, progress?: (current: number, total: number) => void): Promise<boolean> {
        return this.client.putFileContents(path, content, {
            overwrite: !append,
            onUploadProgress: (e) => {
                if (progress) {
                    progress(e.loaded, e.total);
                }
            }
        });
    }

    read<ArrayBuffer>(path: string, progress?: (current: number, total: number) => void): Promise<ArrayBuffer> {
        return this.client.getFileContents(path, {
            onDownloadProgress: (e) => {
                if (progress) {
                    progress(e.loaded, e.total)
                }
            }
        });
    }

    write<T>(path: string, content: T, progress?: (current: number, total: number) => void): Promise<boolean> {
        return new Promise<boolean>((resolve, reject) => {
            let file = new FileReader();
            file.onload = (evt: ProgressEvent<FileReader>) => {
                if (!evt.target) {
                    resolve(false);
                    return;
                }
                this.client.putFileContents(path, evt.target.result, {
                    overwrite: false,
                    onUploadProgress: (e) => {
                        if (progress) {
                            progress(e.loaded, e.total);
                        }
                    }
                }).then(() => resolve(true))
                    .catch(e => reject(e));
            }
            file.readAsArrayBuffer(content as File);
        })
    }

}